/**
 * 
 */
package com.huyi.lock.zookeeperlock;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

/**
 * 描述：
 * 
 * @author shengli.hu
 * @since 1.8
 * @version 1.0
 */
public class ZookeeperLock implements Lock {

	private ZooKeeper zk = null;
	private String lockPath;
	// 当前虚拟节点
	private String currentZnode;
	
	private CountDownLatch latch = null;

	/**
	 * 构造方法
	 * 
	 * @param zkConnString
	 * @param lockName
	 */
	public ZookeeperLock(String zkhost, String lockPath) {
		this.lockPath = lockPath;
		// 创建一个与服务器的连接
		try {
			zk = new ZooKeeper(zkhost, 3000, null);
			Stat stat = zk.exists(lockPath, false);
			if (stat == null) {
				// 创建根节点
				zk.create(lockPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
			}
		} catch (IOException | KeeperException | InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 加锁
	 * 
	 */
	@Override
	public void lock() {
		// 尝试获取锁
		if (tryLock()) {
			return;
		}
	}

	/**
	 * 尝试获取锁
	 * 
	 */
	@Override
	public boolean tryLock() {
		
		try {
			// 创建有许虚拟节点
			currentZnode = zk.create(lockPath + "/test_lock_", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
			
			// 获取所有子节点，判断当前是否最新
			List<String> nodes = zk.getChildren(lockPath, true);
			if(nodes.size() == 0) {
				return true;
			}
			
			// 排序
			Collections.sort(nodes);
			if(!currentZnode.equals(lockPath +"/"+ nodes.get(0))) {
				if(this.latch == null) {
					latch = new CountDownLatch(1);
					
					// 监控它前一个节点是否删除
					String preNode = "";
					for(int i =0;i<nodes.size();i++) {
						if(currentZnode.equals(lockPath +"/"+ nodes.get(i))) {
							preNode = nodes.get(i-1);
							break;
						}
					}
					
					zk.exists(lockPath + "/" + preNode, new Watcher(){
						@Override
						public void process(WatchedEvent event) {
							if(event.getType().equals(Event.EventType.NodeDeleted)) {
								latch.countDown();
								System.out.println("已经触发了" + event.getType() + "事件！"); 
							}

						}
					});
					latch.await();
					System.out.println(Thread.currentThread().getName() + "得到通知，停止等待"); 
				}
			}
			System.out.println(Thread.currentThread().getName() + "获取到锁！！"); 
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return false;
	}

	@Override
	public void unlock() {
		try {
			zk.delete(currentZnode,-1);
			System.out.println(Thread.currentThread().getName() + "锁已释放！！"); 
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (KeeperException e) {
			e.printStackTrace();
		}
	}

	@Override
	public Condition newCondition() {
		return null;
	}

	@Override
	public void lockInterruptibly() throws InterruptedException {

	}

}
